package tk.amberide.engine.al; import tk.amberide.ide.gui.misc.ErrorHandler; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.IntBuffer; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.HashMap; import javax.sound.sampled.AudioFileFormat; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.DataLine; import javax.sound.sampled.Line; import javax.sound.sampled.Mixer; import javax.sound.sampled.SourceDataLine; import org.lwjgl.BufferUtils; import org.lwjgl.openal.AL; import static org.lwjgl.openal.AL10.*; import org.lwjgl.util.WaveData; public class AudioIO extends Object { private static final HashMap<String, AudioCodec> codecs = new HashMap<String, AudioCodec>(); private static boolean al; public static final AudioCodec CODEC_AIF = new AudioCodec() { public Audio readAudio(InputStream in) throws Exception { if (!al) { return CODEC_JAVASOUND.readAudio(in); } AudioInputStream ais = AudioSystem.getAudioInputStream(in); AudioFormat af = ais.getFormat(); int buffer = -1; try { IntBuffer buf = BufferUtils.createIntBuffer(1); AiffDecoder data = AiffDecoder.create(ais); alGenBuffers(buf); alBufferData(buf.get(0), data.format, data.data, data.samplerate); buffer = buf.get(0); } catch (Exception e) { ErrorHandler.alert(e); } if (buffer == -1) { throw new IOException("unable to load: " + in); } ALAudio ala = new ALAudio(buffer, af); return ala; } }; public static final AudioCodec CODEC_WAV = new AudioCodec() { public Audio readAudio(InputStream in) throws Exception { if (!al) { return CODEC_JAVASOUND.readAudio(in); } AudioInputStream ais = AudioSystem.getAudioInputStream(in); AudioFormat af = ais.getFormat(); int buffer = -1; try { IntBuffer buf = BufferUtils.createIntBuffer(1); WaveData data = WaveData.create(ais); alGenBuffers(buf); alBufferData(buf.get(0), data.format, data.data, data.samplerate); buffer = buf.get(0); } catch (Exception e) { ErrorHandler.alert(e); } if (buffer == -1) { throw new IOException("unable to load: " + in); } ALAudio ala = new ALAudio(buffer, af); return ala; } }; public static final AudioCodec CODEC_OGG = new AudioCodec() { public Audio readAudio(InputStream in) throws Exception { if (!al) { throw new IllegalStateException("cannot get ogg audio: AL context unavailable"); } BufferedInputStream bais = new BufferedInputStream(in); int buffer = -1; AudioFileFormat format = null; try { IntBuffer buf = BufferUtils.createIntBuffer(1); OggDecoder decoder = new OggDecoder(bais); alGenBuffers(buf); alBufferData(buf.get(0), decoder.channels > 1 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16, decoder.data, decoder.rate); OggDecoder.Stream aux = decoder.oggInput; buffer = buf.get(0); AudioFormat base = new AudioFormat(aux.getRate(), 16, alGetBufferi(buffer, AL_CHANNELS), true, aux.bigEndian); format = new AudioFileFormat( new AudioFileFormat.Type("OGG", "ogg"), base, (int) (base.getFrameRate() * (((alGetBufferi(buffer, AL_SIZE) / (alGetBufferi(buffer, AL_BITS) / 8)) / (float) alGetBufferi(buffer, AL_FREQUENCY)) / alGetBufferi(buffer, AL_CHANNELS) / 1000000 + 4))); } catch (Exception e) { ErrorHandler.alert(e); } if (buffer == -1) { throw new IOException("unable to load: " + in); } ALAudio ala = new ALAudio(buffer, format.getFormat()); return ala; } }; public static final AudioCodec CODEC_MIDI = new AudioCodec() { public MidiAudio readAudio(InputStream in) throws Exception { return new MidiAudio(in); } }; public static final AudioCodec CODEC_JAVASOUND = new AudioCodec() { public JSAudio readAudio(InputStream in) throws Exception { return new JSAudio(AudioSystem.getAudioInputStream(in)); } }; static { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { try { AL.create(); } catch (Exception e) { ErrorHandler.alert(e); } al = AL.isCreated(); return null; } }); codecs.put("AIF", CODEC_AIF); codecs.put("WAV", CODEC_WAV); codecs.put("OGG", CODEC_OGG); codecs.put("MIDI", CODEC_MIDI); codecs.put("MID", CODEC_MIDI); } public static Audio read(File file) throws Exception { String fileName = file.getName(); String extension = ""; int i = fileName.lastIndexOf('.'); if (i > fileName.lastIndexOf(File.pathSeparator)) { extension = fileName.substring(i + 1); } return read(extension, new BufferedInputStream(new FileInputStream(file))); } public static Audio read(String format, InputStream in) throws Exception { format = format.toUpperCase(); if (codecs.containsKey(format)) { return codecs.get(format).readAudio(in); } throw new IOException("unsupported format for Audio: " + format); } public static AudioCodec getCodec(String format) { return codecs.get(format.toUpperCase()); } public static void addCodec(String format, AudioCodec codec) { codecs.put(format.toUpperCase(), codec); } public static Mixer findMixer(AudioFormat format) { DataLine.Info lineInfo = new DataLine.Info(SourceDataLine.class, format); Mixer.Info[] mixerInfos = AudioSystem.getMixerInfo(); //check each available mixer to see if it is acceptable for (int i = 0; i < mixerInfos.length; i++) { Mixer mixer = AudioSystem.getMixer(mixerInfos[i]); //first check if it supports our line if (!mixer.isLineSupported(lineInfo)) { continue; //nope } //now check if we've used up our lines int maxLines = mixer.getMaxLines(lineInfo); //if it's not specified, it's supposedly unlimited if (maxLines == AudioSystem.NOT_SPECIFIED) { return mixer; } //otherwise we should count them int linesOpen = 0; Line[] sourceLines = mixer.getSourceLines(); for (int s = 0; s < sourceLines.length; s++) { //check if it matches our line if (sourceLines[s].getLineInfo().matches(lineInfo)) { linesOpen++; //one line used up } } //now we can see if any are available if (maxLines > linesOpen) { return mixer; } } //couldn't find one return null; } public static AudioFormat getFormat(InputStream in) { try { AudioFormat af = AudioSystem.getAudioInputStream(new BufferedInputStream(in)).getFormat(); System.out.println(af); return af; } catch (Exception e) { e.printStackTrace(); } return null; } }